#pragma once

#include <iostream>
#include <pthread.h>
#include <queue>
#include "Cond.hpp"
#include "Mutex.hpp"

static int qmsize = 10;

namespace My_BlockQueue
{
    template <class T>
    class BlockQueue
    {
    private:
        bool IfFull() { return _q.size() == _msize; }
        bool IfEmpty() { return _q.empty(); }

    public:
        BlockQueue(int msize = qmsize) : _msize(msize)
        {
            _cwait_num = _pwait_num = 0;
        }
        void Push(const T &data)
        {
            My_Mutex::LockGuard lockguard(_mutex);

            while (IfFull())
            {
                std::cout << "producter等待中..." << std::endl;
                _pwait_num++;
                _producter.Wait(_mutex);
                _pwait_num--;
                std::cout << "producter被唤醒..." << std::endl;

            }

            _q.push(data);

            if(_cwait_num)
            {
                _consumer.Weak();
            }

        }

        void Pop(T &data)
        {
            My_Mutex::LockGuard lockguard(_mutex);

            while (IfEmpty())
            {
                std::cout << "consumer等待中..." << std::endl;

                _cwait_num++;
                _consumer.Wait(_mutex);
                _cwait_num--;

                std::cout << "consumer被唤醒..." << std::endl;
            }

            data = _q.front();
            _q.pop();

            if(_pwait_num)
            {
                _producter.Weak();
            }

        }

        ~BlockQueue()
        {

        }

    private:
        std::queue<T> _q;
        int _msize;
        My_Mutex::Mutex _mutex;
        My_Cond::Cond _producter;
        My_Cond::Cond _consumer;

        int _pwait_num;
        int _cwait_num;
    };
}



// static int qmsize = 10;

// namespace BlockQueueModule
// {
//     template <class T>
//     class BlockQueue
//     {
//     private:
//         bool IfFull() { return _q.size() == _msize; }
//         bool IfEmpty() { return _q.empty(); }

//     public:
//         BlockQueue(int msize = qmsize) : _msize(msize)
//         {
//             _cwait_num = _pwait_num = 0;
//             pthread_mutex_init(&_mutex, nullptr);
//             pthread_cond_init(&_producter, nullptr);
//             pthread_cond_init(&_consumer, nullptr);
//         }
//         void Push(const T &data)
//         {
//             pthread_mutex_lock(&_mutex);

//             while (IfFull())
//             {
//                 std::cout << "producter等待中..." << std::endl;
//                 _pwait_num++;
//                 pthread_cond_wait(&_producter, &_mutex);
//                 _pwait_num--;
//                 std::cout << "producter被唤醒..." << std::endl;

//             }

//             _q.push(data);

//             if(_cwait_num)
//             {
//                 pthread_cond_signal(&_consumer);
//             }

//             pthread_mutex_unlock(&_mutex);
//         }

//         void Pop(T &data)
//         {
//             pthread_mutex_lock(&_mutex);

//             while (IfEmpty())
//             {
//                 std::cout << "consumer等待中..." << std::endl;

//                 _cwait_num++;
//                 pthread_cond_wait(&_consumer, &_mutex);
//                 _cwait_num--;

//                 std::cout << "consumer被唤醒..." << std::endl;
//             }

//             data = _q.front();
//             _q.pop();

//             if(_pwait_num)
//             {
//                 pthread_cond_signal(&_producter);
//             }

//             pthread_mutex_unlock(&_mutex);
//         }

//         ~BlockQueue()
//         {
//             pthread_mutex_destroy(&_mutex);
//             pthread_cond_destroy(&_producter);
//             pthread_cond_destroy(&_consumer);
//         }

//     private:
//         std::queue<T> _q;
//         int _msize;
//         pthread_mutex_t _mutex;
//         pthread_cond_t _producter;
//         pthread_cond_t _consumer;

//         int _pwait_num;
//         int _cwait_num;
//     };
// }
